//
//  NSStringAdditions.m
//  Tint
//
//  Created by Kevin Wu on 2/22/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "NSStringAdditions.h"
#import "NSDataAdditions.h"
#import "NSDictionaryAdditions.h"


@implementation NSString (Tint)


#pragma mark - Creating

+ (NSString *)newUUIDString
{
	CFUUIDRef object = CFUUIDCreate(NULL);
	NSString *string = (NSString *)CFUUIDCreateString(NULL, object);
    if ( object ) {
        CFRelease(object);
        object = nil;
    }
    return string;
}

+ (NSString *)newRandStringWithLength:(NSUInteger)length
{
    if ( length > 0 ) {
        static NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
        NSUInteger lettersLength = [letters length];
        
        NSMutableString *string = [[NSMutableString alloc] init];
        for ( NSUInteger i=0; i<length; i++ ) {
            [string appendFormat:@"%c", [letters characterAtIndex:arc4random() % lettersLength]];
        }
        return string;
    }
    return [[NSString alloc] init];
}

+ (NSString *)newRandAlphanumericStringWithLength:(NSUInteger)length
{
    if ( length > 0 ) {
        static NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY";
        NSUInteger lettersLength = [letters length];
        
        NSMutableString *string = [[NSMutableString alloc] init];
        for ( NSUInteger i=0; i<length; i++ ) {
            [string appendFormat:@"%c", [letters characterAtIndex:arc4random() % lettersLength]];
        }
        return string;
    }
    return [[NSString alloc] init];
}


- (NSData *)newDataUsingUTF8StringEncoding
{
    return [self newDataUsingEncoding:NSUTF8StringEncoding];
}

- (NSData *)newDataUsingASCIIStringEncoding
{
    return [self newDataUsingEncoding:NSASCIIStringEncoding];
}

- (NSData *)newDataUsingEncoding:(NSStringEncoding)encoding
{
    return [[NSData alloc] initWithBytes:[self cStringUsingEncoding:encoding] length:[self lengthOfBytesUsingEncoding:encoding]];
}



#pragma mark - Hash

- (NSString *)newMD5HashString
{
    NSData *data = [self newDataUsingUTF8StringEncoding];
    NSString *md5 = [data newMD5HashString];
    [data release];
    return md5;
}

- (NSString *)newSHA1HashString
{
    NSData *data = [self newDataUsingUTF8StringEncoding];
    NSString *sha1 = [data newSHA1HashString];
    [data release];
    return sha1;
}




#pragma mark - Validity

- (BOOL)isWhitespaceAndNewlines
{
    NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    for ( int i=0; i<[self length]; ++i ) {
        unichar c = [self characterAtIndex:i];
        if ( ![characterSet characterIsMember:c] ) {
            return NO;
        }
    }
    return YES;
}

- (BOOL)isEmailAddress
{
    NSString *regularExpression = 
	@"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}"  
	@"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" 
	@"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-"  
	@"z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5"  
	@"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-"  
	@"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21"  
	@"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";  
	
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regularExpression];  
    return [predicate evaluateWithObject:[self lowercaseString]];  
}

- (BOOL)isNonNegativeNumber
{
    NSCharacterSet *characterSet = [NSCharacterSet decimalDigitCharacterSet];
    for ( int i=0; i<[self length]; ++i ) {
        unichar c = [self characterAtIndex:i];
        if ( ![characterSet characterIsMember:c] ) {
            return NO;
        }
    }
    return YES;
}


#pragma mark - URL

- (NSString *)newURLEncodedString
{
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR("!*'();:@&=+$,/?%#[]<>"), kCFStringEncodingUTF8);
}

- (NSString *)newURLDecodedString
{
    return (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)self, CFSTR(""), kCFStringEncodingUTF8);
}



- (NSDictionary *)newQueryDictionary
{
    NSCharacterSet *delimiterSet = [NSCharacterSet characterSetWithCharactersInString:@"&;"];
    
    NSMutableDictionary *pairs = [[NSMutableDictionary alloc] init];
    
    NSScanner *scanner = [[NSScanner alloc] initWithString:self];
    while ( ![scanner isAtEnd] ) {
        NSString *pairString = nil;
        [scanner scanUpToCharactersFromSet:delimiterSet intoString:&pairString];
        [scanner scanCharactersFromSet:delimiterSet intoString:NULL];
        
        NSArray *pair = [pairString componentsSeparatedByString:@"="];
        
        if (([pair count] == 1) || 
            ([pair count] == 2))
        {
            NSString *key = [[pair objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            
            if ( [pair count] == 1 ) {
                [pairs setObject:[NSNull null] forKey:key];
            } else if ( [pair count] == 2 ) {
                NSString *value = [[pair objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                [pairs setObject:value forKey:key];
            }
        }
    }
    [scanner release];
    
    return pairs;
}

- (NSString *)newStringByAddingQueryDictionary:(NSDictionary *)dictionary
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string addQueryDictionary:dictionary];
    return string;
}

- (NSString *)newStringByAppendingParameter:(NSString *)paramter forKey:(NSString *)key
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string appendParameter:paramter forKey:key];
    return string;
}


#pragma mark - Triming and replacing

- (NSString *)newStringByTrimmingWhitespace
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string trimWhitespace];
    return string;
}

- (NSString *)newStringByTrimmingWhitespaceAndNewline
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string trimWhitespaceAndNewline];
    return string;
}


- (NSString *)newStringByReplacingString:(NSString *)searchString withString:(NSString *)newString
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string replaceString:searchString withString:newString];
    return string;
}

- (NSString *)newStringByReplacingString:(NSString *)searchString withString:(NSString *)newString ignoringCase:(BOOL)ignore
{
    NSMutableString *string = [[NSMutableString alloc] initWithString:self];
    [string replaceString:searchString withString:newString ignoringCase:ignore];
    return string;
}



#pragma mark - Finding and comparing

- (BOOL)containsString:(NSString *)string
{
    return [self containsString:string ignoringCase:NO];
}

- (BOOL)containsString:(NSString *)string ignoringCase:(BOOL)ignore
{
    NSStringCompareOptions options = NSLiteralSearch;
    if ( ignore ) {
        options = NSCaseInsensitiveSearch;
    }
    NSRange range = [self rangeOfString:string options:options];
	return ( range.location != NSNotFound );
}


- (BOOL)equalsToString:(NSString *)string
{
    return [self equalsToString:string ignoringCase:NO];
}

- (BOOL)equalsToString:(NSString *)string ignoringCase:(BOOL)ignore
{
    NSStringCompareOptions options = NSLiteralSearch;
    if ( ignore ) {
        options = NSCaseInsensitiveSearch;
    }
    return ( [self compare:string options:options] == NSOrderedSame );
}

@end






@implementation NSMutableString (Tint)


#pragma mark - URL

- (void)addQueryDictionary:(NSDictionary *)dictionary
{
    NSString *string = [dictionary newQueryString];
    if ( string ) {
        
        if ( [self rangeOfString:@"?"].location == NSNotFound ) {
            [self appendString:@"?"];
        }
        
        if (![self hasSuffix:@"&"] && 
            ![self hasSuffix:@"?"])
        {
            [self appendString:@"&"];
        }
        
        [self appendString:string];
    }
    [string release];
}

- (void)appendParameter:(NSString *)paramter forKey:(NSString *)key
{
    if ( [key length] > 0 ) {
        
        if ( [self rangeOfString:@"?"].location == NSNotFound ) {
            [self appendString:@"?"];
        }
        
        if (![self hasSuffix:@"&"] && 
            ![self hasSuffix:@"?"])
        {
            [self appendString:@"&"];
        }
        
        NSString *encoded = [paramter newURLEncodedString];
        [self appendFormat:@"%@=%@", key, encoded];
        [encoded release];
    }
}



#pragma mark - Triming and replacing

- (void)trimWhitespace
{
    NSString *trimmed = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; // AUTO
    if ( trimmed ) {
        [self setString:trimmed];
    }
}

- (void)trimWhitespaceAndNewline {
    NSString *trimmed = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; // AUTO
    if ( trimmed ) {
        [self setString:trimmed];
    }
}


- (void)replaceString:(NSString *)searchString withString:(NSString *)newString
{
    [self replaceString:searchString withString:newString ignoringCase:NO];
}

- (void)replaceString:(NSString *)searchString withString:(NSString *)newString ignoringCase:(BOOL)ignore
{
    NSStringCompareOptions options = NSLiteralSearch;
    if ( ignore ) {
        options = NSCaseInsensitiveSearch;
    }
    [self replaceOccurrencesOfString:searchString withString:newString options:options range:NSMakeRange(0, [self length])];
}

@end

